#include "redis.hpp"
#include <iostream>

Redis::Redis()
:_publish_context(nullptr), _subscribe_context(nullptr)
{}

Redis::~Redis()
{
    if (_publish_context) {
        redisFree(_publish_context);
    }
    if (_subscribe_context) {
        redisFree(_subscribe_context);
    }
}

bool Redis::Connect()
{
    // 负责publish发布消息的上下文连接
    _publish_context = redisConnect("127.0.0.1", 6379);
    if (_publish_context == nullptr) {
        std::cerr << "connect redis failed!" << std::endl;
        return false;
    }

    // 负责subscri订阅消息的上下文连接
    _subscribe_context = redisConnect("127.0.0.1", 6379);
    if (_subscribe_context == nullptr) {
        std::cerr << "connect redis failed!" << std::endl;
        return false;
    }

    // 单独的线程监听通道上的事件,有消息则给业务层上报
    std::thread t([&]() {
        ObserverChannelMessage();
    });
    t.detach();

    std::cout << "connect redis-server success!" << std::endl;
    return true;
}

bool Redis::Publish(int channel, std::string message)
{
    redisReply* reply = (redisReply*)redisCommand(_publish_context, "PUBLISH %d %s", channel, message.c_str());
    if (reply == nullptr) {
        std::cerr << "publish command failed!" << std::endl;
        return false;
    }
    freeReplyObject(reply);
    return true;
}

bool Redis::Subscribe(int channel)
{
    if (REDIS_ERR == redisAppendCommand(this->_subscribe_context, "SUBSCRIBE %d", channel)) {
        std::cerr << "subscribe command failed!" << std::endl;
        return false;
    }

    // redisBufferWrite可以循环发送缓冲区,知到缓冲区数据发送完毕(done被置为1)
    int done = 0;
    while (!done) {
        if (REDIS_ERR == redisBufferWrite(this->_subscribe_context, &done)) {
            std::cerr << "subscribe command failed!" << std::endl;
            return false;
        }
    }
    return true;
}

bool Redis::Unsubscribe(int channel)
{
    if (REDIS_ERR == redisAppendCommand(this->_subscribe_context, "UNSUBSCRIBE %d", channel)) {
        std::cerr << "unsubscribe command failed!" << std::endl;
        return false;
    }
    int done = 0;
    while (!done) {
        if (REDIS_ERR == redisBufferWrite(this->_subscribe_context, &done)) {
            std::cerr << "unsubscribe command failed!" << std::endl;
            return false;
        }
    }
    return true;
}

void Redis::ObserverChannelMessage()
{
    redisReply* reply = nullptr;
    while (REDIS_OK == redisGetReply(this->_subscribe_context, (void**)&reply)) {
        // 订阅收到的消息是一个带三元素的数组
        if (reply != nullptr && reply->element[2] != nullptr && reply->element[2]->str != nullptr) {
            // 给业务层上报通道上的消息
            _notify_message_handler(atoi(reply->element[1]->str), reply->element[2]->str);
        }
        freeReplyObject(reply);
    }
}

void Redis::InitNotifyHandler(std::function<void(int, std::string)> fn)
{
    this->_notify_message_handler = fn;
}